package org.yoki.edu.common.protocol.radius.attribute.attr;

import lombok.Data;
import lombok.Getter;
import lombok.ToString;
import org.yoki.edu.common.protocol.radius.exception.RadiusBytesLengthErrorException;
import org.yoki.edu.common.protocol.radius.exception.RadiusException;

/**
 * @author Sky$
 * @Description: TODO
 * @date 2017/10/24$ 20:44$
 */
@ToString(exclude = {"valueRawBytes"})
@Data
public abstract class RawRadiusMsgAttr {

    /**
     * type 属性长度
     */
    public static final int LENGTH_TYPE = 1;
    /**
     * code 属性在数组中的下标：0
     */
    public static final int INDEX_TYPE = 0;
    /**
     * length 属性长度
     */
    public static final int LENGTH_LENGTH = 1;
    /**
     * length 属性在数组中的下标：1
     */
    public static final int INDEX_LENGTH = INDEX_TYPE + LENGTH_TYPE;

    /**
     * value 属性在数组中的下标：2
     */
    public static final int INDEX_VALUE = INDEX_LENGTH + LENGTH_LENGTH;

    /**
     * 1 bytes
     */
    @Getter
    protected int type;
    /**
     * 1 bytes
     */
    @Getter
    protected int length;
    /**
     * (length - 1) bytes
     */
    protected byte[] valueRawBytes;

    public RawRadiusMsgAttr() {
        type = getAttrType();
    }

    /**
     * 获取属性类别<br></br>
     * <span color=red><b>子类进行复写此方法</b></span>
     *
     * @return
     */
    public abstract int getAttrType();

    protected void parseRaw(int typeIn, byte[] attrValueIn) {
        if (typeIn > (Byte.MAX_VALUE - Byte.MIN_VALUE)) {
            throw new IndexOutOfBoundsException();
        }
        if (null == attrValueIn) {
            throw new NullPointerException();
        }
        int lengthIn = LENGTH_TYPE + LENGTH_LENGTH + attrValueIn.length;
        if (getAttrType() != typeIn) {
            throw new IllegalArgumentException("不能将数据转化为此类型的Attribution，Type不一致 !!! " +
                    "当前要求的type为 [" + getAttrType() + "]，传入的type为 [" + typeIn + "]");
        }
        //重置所有属性
        rest();
        type = typeIn & 0xff;
        length = lengthIn & 0xff;
        valueRawBytes = attrValueIn;
    }

    protected void parseRaw(byte[] bytes) throws RadiusException {
        if (null == bytes) {
            throw new NullPointerException();
        }
        if (bytes.length < (LENGTH_TYPE + LENGTH_LENGTH)) {
            throw new IndexOutOfBoundsException();
        }
        int type = bytes[0] & 0xFF;
        int length = bytes[1] & 0xFF;
        //判断长度是否合法
        if (bytes.length != length) {
            throw new RadiusBytesLengthErrorException();
        }
        //判断类型是否合法
        if (getAttrType() != type) {
            throw new IllegalArgumentException("不能将数据转化为此类型的Attribution，Type不一致 !!! " +
                    "当前要求的type为 [" + getAttrType() + "]，传入的type为 [" + type + "]");
        }
        //重置所有属性
        rest();
        this.type = type;
        this.length = length;
        byte[] valueByte = new byte[length - (LENGTH_TYPE + LENGTH_LENGTH)];
        System.arraycopy(bytes, (LENGTH_TYPE + LENGTH_LENGTH), valueByte, 0, valueByte.length);
        this.valueRawBytes = valueByte;
    }

    protected void rest() {
        this.type = -1;
        this.length = -1;
        this.valueRawBytes = null;
    }

}
